
#include "stdinc.h"
#include "AsmCall.h"


#pragma optimize( "", off )
void AsmCall::call() 
{
	AsmCall *obj = this;
	_asm
	{
		//int 3;
		pushad;											// save current state of ALL registers
		mov ebx, [obj];									// get our this pointer
		mov ecx, [ebx].mAddress;						// get the target address
		mov eax, [ebx].mStackSize;						// argument count
		lea esi, [ebx].mStack;							// argument list
		push ebx;										// object pointer
		push 0xBAAD57AC;								// bad stack test - a "security cookie"
stackLoop:	cmp eax,0;										// no arguments (left) to push?
		je setRegs;										// go to saving registers
		dec eax;										// still some left - decrease our counter
		push [esi + eax *4];							// push our "stack" variable on the real stack
		jmp stackLoop;									// repeat loop

		//do not use any stack variables beyond this point
setRegs:	push ecx;										// our call address
		mov eax, [ebx].mInputRegisters[_EAX*4].ue;		// save our prepared register states
		mov ecx, [ebx].mInputRegisters[_ECX*4].ue;
		mov edx, [ebx].mInputRegisters[_EDX*4].ue;
		mov esi, [ebx].mInputRegisters[_ESI*4].ue;
		mov edi, [ebx].mInputRegisters[_EDI*4].ue;
		mov ebp, [ebx].mInputRegisters[_EBP*4].ue;
		mov ebx, [ebx].mInputRegisters[_EBX*4].ue;
		add esp,4;										// move the stack to the position expected
		call [esp-4];									// call the value saved on stack
		cmp [esp],0xBAAD57AC;							// check our "security cookie"
		je allGood;										// function cleaned it's arguments, stack should be ok  
		push eax;										// arguments not cleaned make some helper registers
		push ebx;										 
		push ecx;
		mov eax,esp;									// save esp state
		add esp, 0xC;									// move to former stack location 
stackCheck:	add esp, 0x4;									// move to next stack position 
		cmp [esp],0xBAAD57AC;							// have we got our "cookie"?
		je  argTest;									// found it, check the argument count 
		mov ecx,esp;int 3;									// move esp to a temp register
		sub ecx,eax;									// get the difference of esp and saved esp (in eax)   
		shr ecx,2;										// divide by 4 (4 bytes per each 32 bit register)
		cmp ecx,20+3;									// 20 arguments + 3 saved registers (eax,ebx,ecx)
		jbe stackCheck;									// if not Below or Equal test another round
		int 3;											// if Equal (limit reached), die
argTest:	mov ebx, [esp+4];
		mov ecx,esp;									// move esp to a temp register
		sub ecx,eax; 									// get the difference of esp and saved esp (in eax)   
		shr ecx,2;										// divide by 4 to get the argument count
		sub ecx, [ebx].mStackSize;						// subtract the original argument count
		cmp ecx, 3;										// should be 3 (3 saved registers) 
		je endTest;										// it's 3 - end testing
		int 3;											// it wasn't 3 - jump off a bridge
endTest:	mov ecx,[eax];									// original ecx value
		mov ebx,[eax+0x4];								// original ebx value
		mov eax,[eax+0x8];								// original eax value
allGood:	add esp,4;										// remove the security cookie
		push eax;										// store the value of eax 
		mov eax,[esp+4];								// the stored value of obj pointer;
		mov [eax].mOutputRegisters[_EBX*4].ue,ebx;		// save the after-call registers
		mov [eax].mOutputRegisters[_ECX*4].ue,ecx;	
		mov [eax].mOutputRegisters[_EDX*4].ue,edx;
		mov [eax].mOutputRegisters[_ESI*4].ue,esi;
		mov [eax].mOutputRegisters[_EDI*4].ue,edi;
		mov [eax].mOutputRegisters[_EBP*4].ue,ebp;
		pop ebx;										// the value of eax stored after call
		mov [eax].mOutputRegisters[_EAX*4].ue,ebx;
		add esp,4;										// remove the ebx pushed before 0xBAAD57AC
		popad;
	}
};
#pragma optimize( "", on )
